using System;
using System.Collections.Generic;
using System.Linq;
using Sandbox.Definitions;
using Sandbox.Game.Entities;
using Sandbox.ModAPI;
using VRage.Game.ModAPI;
using VRage.ModAPI;
using VRageMath;
using ModularEncountersSpawner.Configuration;
using ModularEncountersSpawner.Templates;
using ModularEncountersSpawner.Manipulation;
using ModularEncountersSpawner.World;
using ModularEncountersSpawner.Zones;

namespace ModularEncountersSpawner.Spawners {

	public static class PlanetaryCargoShipSpawner{
		
		public static Dictionary<string, List<ImprovedSpawnGroup>> SpawnGroupSublists = new Dictionary<string, List<ImprovedSpawnGroup>>();
		public static Dictionary<string, int> EligibleSpawnsByModId = new Dictionary<string, int>();
		
		public static string AttemptSpawn(Vector3D startCoords, List<string> eligibleNames = null) {

			if (!MES_SessionCore.SpawnerEnabled) {

				return "Spawner Disabled Due To Incompatible World Settings (Selective Physics Updates)";

			}

			if (Settings.General.UseMaxNpcGrids == true){
				
				var totalNPCs = NPCWatcher.ActiveNPCs.Count;
				
				if(totalNPCs >= Settings.General.MaxGlobalNpcGrids){
					
					return "Spawning Aborted. Max Global NPCs Limit Reached.";
					
				}
				
			}
			
			if(NPCWatcher.ActiveNpcTypeLimitReachedForArea("PlanetaryCargoShip", startCoords, Settings.PlanetaryCargoShips.MaxShipsPerArea, Settings.PlanetaryCargoShips.AreaSize) == true){
				
				return "Too Many Planetary Cargo Ship Grids in Player Area";
				
			}
			
			MyPlanet planet = SpawnResources.GetNearestPlanet(startCoords);


			
			KnownPlayerLocationManager.CleanExpiredLocations();
			var validFactions = new Dictionary<string, List<string>>();
			var environment = new EnvironmentEvaluation(startCoords);
			var spawnGroupList = GetPlanetaryCargoShips(startCoords, eligibleNames, environment, out validFactions);
			
			if(Settings.General.UseModIdSelectionForSpawning == true){
				
				spawnGroupList = SpawnResources.SelectSpawnGroupSublist(SpawnGroupSublists, EligibleSpawnsByModId);
				
			}

			if(spawnGroupList.Count == 0){
				
				return "No Eligible Spawn Groups Could Be Found To Spawn Near Player.";
				
			}
			
			var spawnGroup = spawnGroupList[SpawnResources.rnd.Next(0, spawnGroupList.Count)];
			
			Vector3D startPathCoords = Vector3D.Zero;
			Vector3D endPathCoords = Vector3D.Zero;
			MatrixD startMatrix = MatrixD.CreateWorld(Vector3D.Zero, Vector3D.Forward, Vector3D.Up);
			
			bool successfulPath = CalculateAtmoTravelPath(spawnGroup, startCoords, environment, out startPathCoords, out endPathCoords, out startMatrix);
			
			if(successfulPath == false){
				
				return "Could Not Generate Safe Travel Path For SpawnGroup.";
				
			}
			
			//Get Directions
			var spawnForwardDir = startMatrix.Forward;
			var spawnUpDir = startMatrix.Up;
			var spawnMatrix = startMatrix;
			var despawnMatrix = MatrixD.CreateWorld(endPathCoords, startMatrix.Forward, startMatrix.Up);
			long gridOwner = 0;
			var randFactionTag = spawnGroup.FactionOwner;

			if(validFactions.ContainsKey(spawnGroup.SpawnGroupName)) {

				randFactionTag = validFactions[spawnGroup.SpawnGroupName][SpawnResources.rnd.Next(0, validFactions[spawnGroup.SpawnGroupName].Count)];

			}

			if(NPCWatcher.NPCFactionTagToFounder.ContainsKey(randFactionTag) == true) {

				gridOwner = NPCWatcher.NPCFactionTagToFounder[randFactionTag];

			} else {

				Logger.AddMsg("Could Not Find Faction Founder For: " + randFactionTag);

			}


			SpawnResources.ApplySpawningCosts(spawnGroup, randFactionTag);


			foreach (var prefab in spawnGroup.SpawnGroup.Prefabs){

				if (spawnGroup.UseKnownPlayerLocations) {

					KnownPlayerLocationManager.IncreaseSpawnCountOfLocations(startCoords, randFactionTag);

				}

				var options = SpawnGroupManager.CreateSpawningOptions(spawnGroup, prefab);
				var spawnPosition = Vector3D.Transform((Vector3D)prefab.Position, spawnMatrix);
				var despawnPosition = Vector3D.Transform((Vector3D)prefab.Position, despawnMatrix);
				var speedL = prefab.Speed;
				var speedA = Vector3.Zero;
				var gridList = new List<IMyCubeGrid>();
				
				
				//Speed Management
				if(Settings.PlanetaryCargoShips.UseMinimumSpeed == true && prefab.Speed < Settings.PlanetaryCargoShips.MinimumSpeed){
					
					speedL = Settings.PlanetaryCargoShips.MinimumSpeed;
					
				}
				
				if(Settings.PlanetaryCargoShips.UseSpeedOverride == true){
					
					speedL = Settings.PlanetaryCargoShips.SpeedOverride;
					
				}
				
				
				
				/*//Character Injection - Start
				MyPrefabDefinition prefabDefB = null;
				
				if(SpawnGroupManager.prefabBackupList.ContainsKey(prefab.SubtypeId) == true){
					
					prefabDefB = MyDefinitionManager.Static.GetPrefabDefinition(prefab.SubtypeId);
					
					if(SpawnGroupManager.prefabBackupList[prefab.SubtypeId].Count == prefabDefB.CubeGrids.Length){
						
						for(int i = 0; i < SpawnGroupManager.prefabBackupList[prefab.SubtypeId].Count; i++){
							
							var clonedGridOb = SpawnGroupManager.prefabBackupList[prefab.SubtypeId][i].Clone();
							prefabDefB.CubeGrids[i] = clonedGridOb as MyObjectBuilder_CubeGrid;
							
						}
						
					}
					
					SpawnGroupManager.prefabBackupList.Remove(prefab.SubtypeId);
					
				}
				
				var injectedCharacters = false;
				if(spawnGroup.FillSeatsWithNpcCrew == true){
					
					injectedCharacters = true;
					
					if(prefabDefB == null){
						
						prefabDefB = MyDefinitionManager.Static.GetPrefabDefinition(prefab.SubtypeId);
						
					}
					
					var backupGridList = new List<MyObjectBuilder_CubeGrid>();
					
					for(int i = 0; i < prefabDefB.CubeGrids.Length; i++){
						
						var clonedGridOb = prefabDefB.CubeGrids[i].Clone();
						backupGridList.Add(clonedGridOb as MyObjectBuilder_CubeGrid);
						GridUtilities.CreateAndAttachCrew(prefabDefB.CubeGrids[i], spawnGroup, gridOwner);
						
					}
					
					if(SpawnGroupManager.prefabBackupList.ContainsKey(prefab.SubtypeId) == false){
						
						SpawnGroupManager.prefabBackupList.Add(prefab.SubtypeId, backupGridList);
						
					}
	
				}
				//Character Injection - End*/
				
				//Grid Manipulation
				ManipulationCore.ProcessPrefabForManipulation(prefab.SubtypeId, spawnGroup, "PlanetaryCargoShip", prefab.Behaviour);
				
				try{
					
					MyAPIGateway.PrefabManager.SpawnPrefab(gridList, prefab.SubtypeId, spawnPosition, spawnForwardDir, spawnUpDir, Vector3.Zero, Vector3.Zero, !string.IsNullOrWhiteSpace(prefab.BeaconText) ? prefab.BeaconText : null, options, gridOwner);
					
				}catch(Exception exc){
					
					
					
				}
				
				var pendingNPC = new ActiveNPC();
				pendingNPC.SpawnGroup = spawnGroup;
				pendingNPC.SpawnGroupName = spawnGroup.SpawnGroupName;
				pendingNPC.InitialFaction = randFactionTag;
				pendingNPC.faction = MyAPIGateway.Session.Factions.TryGetFactionByTag(pendingNPC.InitialFaction);
				pendingNPC.Name = prefab.SubtypeId;
				pendingNPC.GridName = MyDefinitionManager.Static.GetPrefabDefinition(prefab.SubtypeId).CubeGrids[0].DisplayName;
				pendingNPC.StartCoords = spawnPosition;
				pendingNPC.CurrentCoords = startPathCoords;
				pendingNPC.EndCoords = despawnPosition;
				pendingNPC.AutoPilotSpeed = speedL;
				pendingNPC.Planet = planet;
				pendingNPC.SpawnType = "PlanetaryCargoShip";
				pendingNPC.CleanupIgnore = spawnGroup.IgnoreCleanupRules;
				pendingNPC.ForceStaticGrid = spawnGroup.ForceStaticGrid;
				pendingNPC.KeenAiName = prefab.Behaviour;
				pendingNPC.KeenAiTriggerDistance = prefab.BehaviourActivationDistance;

				TimeoutManagement.ApplySpawnTimeoutToZones(SpawnType.PlanetaryCargoShip, spawnPosition);

				if (string.IsNullOrEmpty(pendingNPC.KeenAiName) == false) {

					if (RivalAIHelper.RivalAiBehaviorProfiles.ContainsKey(pendingNPC.KeenAiName) && spawnGroup.UseRivalAi) {

						Logger.AddMsg("RivalAI Behavior Detected In Prefab: " + prefab.SubtypeId + " in SpawnGroup: " + spawnGroup.SpawnGroup.Id.SubtypeName);

					} else {

						Logger.AddMsg("Stock AI Detected In Prefab: " + prefab.SubtypeId + " in SpawnGroup: " + spawnGroup.SpawnGroup.Id.SubtypeName);

					}


				}

				if (spawnGroup.RandomizeWeapons == true){
						
					pendingNPC.ReplenishedSystems = false;
					pendingNPC.ReplacedWeapons = true;
					
				}else if((MES_SessionCore.NPCWeaponUpgradesModDetected == true || Settings.Grids.EnableGlobalNPCWeaponRandomizer == true) && spawnGroup.IgnoreWeaponRandomizerMod == false){
				
					pendingNPC.ReplenishedSystems = false;
					pendingNPC.ReplacedWeapons = true;
					
				}else if(spawnGroup.ReplenishSystems == true){
					
					pendingNPC.ReplenishedSystems = false;
					
				}
				
				NPCWatcher.PendingNPCs.Add(pendingNPC);
				
			}

			if (spawnGroup.UniqueEncounter == true) {

				SpawnGroupManager.UniqueGroupsSpawned.Add(spawnGroup.SpawnGroup.Id.SubtypeName);
				string[] uniqueSpawnedArray = SpawnGroupManager.UniqueGroupsSpawned.ToArray();
				MyAPIGateway.Utilities.SetVariable<string[]>("MES-UniqueGroupsSpawned", uniqueSpawnedArray);

			}

			Logger.SkipNextMessage = false;
			return "Spawning Group - " + spawnGroup.SpawnGroup.Id.SubtypeName;
			
		}
		
		public static bool CalculateAtmoTravelPath(ImprovedSpawnGroup spawnGroup, Vector3D startCoords, EnvironmentEvaluation environment, out Vector3D startPathCoords, out Vector3D endPathCoords, out MatrixD startMatrix){
			
			startPathCoords = Vector3D.Zero;
			endPathCoords = Vector3D.Zero;
			startMatrix = MatrixD.CreateWorld(Vector3D.Zero, Vector3D.Forward, Vector3D.Up);
			SpawnResources.RefreshEntityLists();
			
			if(environment.NearestPlanet == null){
				
				return false;
				
			}
			
			var planetEntity = environment.NearestPlanet as IMyEntity;
			bool gravitySpawn = environment.AltitudeAtPosition > Settings.PlanetaryCargoShips.PlayerSurfaceAltitude;

			if ((gravitySpawn && !spawnGroup.GravityCargoShip) && (!gravitySpawn && !spawnGroup.AtmosphericCargoShip))
				return false;

			for(int i = 0; i < Settings.PlanetaryCargoShips.MaxSpawnAttempts; i++){
				
				//Get Starting Point
				var randDirFromPlayer = SpawnResources.GetRandomCompassDirection(startCoords, environment.NearestPlanet);
				var pathDist = SpawnResources.GetRandomPathDist(Settings.PlanetaryCargoShips.MinPathDistanceFromPlayer, Settings.PlanetaryCargoShips.MaxPathDistanceFromPlayer);
				Vector3D midPointSurface = randDirFromPlayer * pathDist + startCoords;

				if(!gravitySpawn)
					midPointSurface = SpawnResources.GetNearestSurfacePoint(randDirFromPlayer * pathDist + startCoords, environment.NearestPlanet);

				if (environment.PlanetWater != null) {

					if (environment.PlanetWater.IsUnderwater(midPointSurface)) {

						midPointSurface = environment.PlanetWater.GetClosestSurfacePoint(midPointSurface);

					}
				
				}
				
				var upDir = Vector3D.Normalize(midPointSurface - planetEntity.GetPosition());
				var altitudeFromMid = SpawnResources.GetRandomPathDist(Settings.PlanetaryCargoShips.MinSpawningAltitude, Settings.PlanetaryCargoShips.MaxSpawningAltitude);

				if (gravitySpawn)
					altitudeFromMid = SpawnResources.GetRandomPathDist(altitudeFromMid * -1, altitudeFromMid);

				var tempStartPath = upDir * altitudeFromMid + midPointSurface;
				var customAltitudeStart = spawnGroup.CustomPathStartAltitude > -1 ? spawnGroup.CustomPathStartAltitude * upDir + midPointSurface : Vector3D.Zero;

				if (!spawnGroup.SkipAirDensityCheck) {

					if (!gravitySpawn && spawnGroup.PlanetRequiresAtmo == true && environment.NearestPlanet.GetAirDensity(tempStartPath) < Settings.PlanetaryCargoShips.MinAirDensity) {

						tempStartPath = upDir * Settings.PlanetaryCargoShips.MinSpawningAltitude + midPointSurface;

						if (spawnGroup.PlanetRequiresAtmo == true && environment.NearestPlanet.GetAirDensity(tempStartPath) < Settings.PlanetaryCargoShips.MinAirDensity) {

							continue;

						}

					}

				}

				if (gravitySpawn && (spawnGroup.MaxGravity != -1 || spawnGroup.MinGravity != -1)) {

					var gravAtTempStart = environment.Gravity.GetGravityMultiplier(tempStartPath);

					if (gravAtTempStart > spawnGroup.MaxGravity || gravAtTempStart < spawnGroup.MinGravity) {

						tempStartPath = midPointSurface;
						gravAtTempStart = environment.Gravity.GetGravityMultiplier(tempStartPath);

						if (gravAtTempStart > spawnGroup.MaxGravity || gravAtTempStart < spawnGroup.MinGravity)
							continue;

					}

				}
				
				if(SpawnResources.IsPositionNearEntities(customAltitudeStart != Vector3D.Zero ? customAltitudeStart : tempStartPath, Settings.PlanetaryCargoShips.MinSpawnFromGrids) == true){
					
					continue;
					
				}
				
				var startCoordsDistFromCenter = Vector3D.Distance(planetEntity.GetPosition(), tempStartPath);
				
				//Get Ending Point
				var randPathDir = SpawnResources.GetRandomCompassDirection(tempStartPath, environment.NearestPlanet);

				if (spawnGroup.CargoShipTerrainPath) {

					var customPathMatrix = MatrixD.CreateWorld(startCoords, randDirFromPlayer, Vector3D.Normalize(startCoords - environment.NearestPlanet.PositionComp.WorldAABB.Center));
					randPathDir = customPathMatrix.Right;

				}
				
				var randPathDist = SpawnResources.GetRandomPathDist(Settings.PlanetaryCargoShips.MinPathDistance, Settings.PlanetaryCargoShips.MaxPathDistance);
				var endPathA = randPathDir * randPathDist + tempStartPath;
				var endPathB = -randPathDir * randPathDist + tempStartPath;
				var tempEndPath = Vector3D.Zero;
				
				if(Vector3D.Distance(endPathA, startCoords) < Vector3D.Distance(endPathB, startCoords)){
					
					tempEndPath = endPathA;
					
				}else{
					
					tempEndPath = endPathB;
					randPathDir *= -1;
					
				}
				
				//TODO: Set At Same Height From Sealevel As Start
				var endUpDir = Vector3D.Normalize(tempEndPath - planetEntity.GetPosition());
				tempEndPath = endUpDir * startCoordsDistFromCenter + planetEntity.GetPosition();
				
				//Check Path
				var tempMatrix = MatrixD.CreateWorld(tempStartPath, randPathDir, upDir);
				var tempCustomPathMatrix = MatrixD.CreateWorld(customAltitudeStart, randPathDir, upDir);
				var truePathDir = Vector3D.Normalize(tempEndPath - tempStartPath);
				bool badPath = false;
				
				foreach(var prefab in spawnGroup.SpawnGroup.Prefabs){

					var modifiedStart = Vector3D.Transform((Vector3D)prefab.Position, tempMatrix);
					double totalSteps = 0;

					if (!spawnGroup.CargoShipTerrainPath || customAltitudeStart == Vector3D.Zero) {

						//Regular Aerial Path
						while (totalSteps < randPathDist) {

							var testPath = totalSteps * truePathDir + modifiedStart;

							if (SpawnResources.IsPositionInSafeZone(testPath) == true) {

								badPath = true;
								break;

							}

							if (SpawnResources.GetDistanceFromSurface(testPath, environment.NearestPlanet) < Settings.PlanetaryCargoShips.MinPathAltitude) {

								badPath = true;
								break;

							}

							if (environment.PlanetWater != null) {

								var pathToWaterDist = Vector3D.Distance(testPath, environment.PlanetWater.GetClosestSurfacePoint(testPath));

								if (environment.PlanetWater.IsUnderwater(testPath) || pathToWaterDist < Settings.PlanetaryCargoShips.MinPathAltitude) {

									badPath = true;
									break;

								}

							}

							totalSteps += Settings.PlanetaryCargoShips.PathStepCheckDistance;

						}

						if (!badPath) {

							var doublePathDist = pathDist * 2;
							var box = new BoundingBoxD(new Vector3D(-1, -1, -1) + tempStartPath, new Vector3D(1, 1, 1) + tempEndPath);

							foreach (var entity in SpawnResources.EntityList) {

								if (Vector3D.Distance(entity.GetPosition(), tempStartPath) > doublePathDist) {

									continue;

								}

								if (entity.WorldAABB.Contains(box) != ContainmentType.Disjoint) {

									var planet = entity as MyPlanet;

									if (planet != null)
										continue;

									var grid = entity as IMyCubeGrid;
									var voxel = entity as IMyVoxelBase;

									if (grid != null || voxel != null) {

										badPath = true;
										break;

									}

								}

							}

						}


					} else {

						//Terrain Path
						var modifiedStartSurface = environment.NearestPlanet.GetClosestSurfacePointGlobal(modifiedStart);
						modifiedStart = upDir * spawnGroup.CustomPathStartAltitude + modifiedStartSurface;

						while (totalSteps < randPathDist) {

							var testPath = totalSteps * truePathDir + modifiedStart;
							var testPathSurface = environment.NearestPlanet.GetClosestSurfacePointGlobal(testPath);
							var actualPathSurface = Vector3D.Normalize(testPathSurface - environment.NearestPlanet.PositionComp.WorldAABB.Center) * spawnGroup.CustomPathStartAltitude + testPathSurface;

							if (SpawnResources.IsPositionInSafeZone(testPath) == true) {

								badPath = true;
								break;

							}

							if (!spawnGroup.SkipAirDensityCheck) {

								var air = environment.NearestPlanet.GetAirDensity(actualPathSurface);

								if (air < Settings.PlanetaryCargoShips.MinAirDensity) {

									badPath = true;
									break;

								}

							}

							totalSteps += Settings.PlanetaryCargoShips.PathStepCheckDistance;

						}

						if (!badPath) {

							var points = new List<Vector3D>();
							points.Add(tempStartPath);
							points.Add(modifiedStart);
							points.Add(truePathDir * randPathDist + modifiedStart);
							points.Add(truePathDir * randPathDist + tempStartPath);

							var box = BoundingBoxD.CreateFromPoints(points);
							var doublePathDist = pathDist * 2;

							foreach (var entity in SpawnResources.EntityList) {

								if (Vector3D.Distance(entity.GetPosition(), tempStartPath) > doublePathDist) {

									continue;

								}

								if (entity.WorldAABB.Contains(box) != ContainmentType.Disjoint) {

									var planet = entity as MyPlanet;

									if (planet != null)
										continue;

									var grid = entity as IMyCubeGrid;

									if (grid != null) {

										badPath = true;
										break;

									}

								}

							}

						}

					}

					if(badPath == true){
						
						break;
						
					}
					
				}
				
				if(badPath == true){
					
					continue;
					
				}
				
				startPathCoords = tempStartPath;

				if (spawnGroup.CustomPathStartAltitude > -1) {

					var surface = environment.NearestPlanet.GetClosestSurfacePointGlobal(startPathCoords);
					startPathCoords = Vector3D.Normalize(surface - environment.NearestPlanet.PositionComp.WorldAABB.Center) * spawnGroup.CustomPathStartAltitude + surface;
					tempMatrix.Translation = startPathCoords;

				}

				endPathCoords = tempEndPath;

				if (spawnGroup.CustomPathEndAltitude > -1) {

					var surface = environment.NearestPlanet.GetClosestSurfacePointGlobal(endPathCoords);
					startPathCoords = Vector3D.Normalize(surface - environment.NearestPlanet.PositionComp.WorldAABB.Center) * spawnGroup.CustomPathEndAltitude + surface;

				}

				startMatrix = tempMatrix;
				return true;
				
			}
			
			return false;
			
		}
				
		public static List<ImprovedSpawnGroup> GetPlanetaryCargoShips(Vector3D playerCoords, List<string> eligibleNames, EnvironmentEvaluation environment, out Dictionary<string, List<string>> validFactions) {

			string specificGroup = "";
			var planetRestrictions = new List<string>(Settings.General.PlanetSpawnsDisableList.ToList());
			validFactions = new Dictionary<string, List<string>>();
			SpawnGroupSublists.Clear();
			EligibleSpawnsByModId.Clear();

			if (!environment.IsOnPlanet || environment.NearestPlanet == null) {

				return new List<ImprovedSpawnGroup>();

			}

			if (environment.NearestPlanet != null && environment.IsOnPlanet) {

				if (planetRestrictions.Contains(environment.NearestPlanetName) == true) {

					return new List<ImprovedSpawnGroup>();

				}

			}

			bool specificSpawnRequest = false;
			
			if(SpawnGroupManager.AdminSpawnGroup != ""){
				
				specificGroup = SpawnGroupManager.AdminSpawnGroup;
				SpawnGroupManager.AdminSpawnGroup = "";
				specificSpawnRequest = true;
				
			}

			var eligibleGroups = new List<ImprovedSpawnGroup>();
			SpawnResources.SandboxVariableCache.Clear();
			bool aboveMaxPlayerAltitude = environment.AltitudeAtPosition > Settings.PlanetaryCargoShips.PlayerSurfaceAltitude;
			Logger.AddMsg("Above PCS Altitude: " + aboveMaxPlayerAltitude, true);

			//Filter Eligible Groups To List
			foreach (var spawnGroup in SpawnGroupManager.SpawnGroups){

				if (eligibleNames != null) {

					if (!eligibleNames.Contains(spawnGroup.SpawnGroupName)) {

						continue;

					}

				} else {

					if (specificGroup != "" && spawnGroup.SpawnGroup.Id.SubtypeName != specificGroup) {

						continue;

					}

					if (specificGroup == "" && spawnGroup.AdminSpawnOnly == true) {

						continue;

					}

				}

				var atmoAllowed = spawnGroup.AtmosphericCargoShip && !aboveMaxPlayerAltitude;
				var gravityAllowed = spawnGroup.GravityCargoShip && aboveMaxPlayerAltitude;

				if (!atmoAllowed && !gravityAllowed) {
					
					continue;
					
				}

				if (spawnGroup.AtmosphericCargoShip && spawnGroup.AtmosphericCargoShipChance < spawnGroup.ChanceCeiling && atmoAllowed && !specificSpawnRequest) {

					var roll = SpawnResources.rnd.Next(0, spawnGroup.ChanceCeiling + 1);

					if (roll > spawnGroup.AtmosphericCargoShipChance)
						continue;

				}

				if (spawnGroup.GravityCargoShip && spawnGroup.GravityCargoShipChance < spawnGroup.ChanceCeiling && gravityAllowed && !specificSpawnRequest) {

					var roll = SpawnResources.rnd.Next(0, spawnGroup.ChanceCeiling + 1);

					if (roll > spawnGroup.GravityCargoShipChance)
						continue;

				}

				if (!spawnGroup.SkipAirDensityCheck && environment.AirTravelViabilityRatio < 0.25f) {

					continue;
				
				}

				//Logger.AddMsg("Before Common Conditions", true);
				if (SpawnResources.CheckCommonConditions(spawnGroup, playerCoords, environment, specificSpawnRequest, SpawnType.PlanetaryCargoShip) == false){
					
					continue;
					
				}
				//Logger.AddMsg("After Common Conditions", true);

				var validFactionsList = SpawnResources.ValidNpcFactions(spawnGroup, playerCoords);

				if(validFactionsList.Count == 0) {

					continue;

				}

				if(validFactions.ContainsKey(spawnGroup.SpawnGroupName) == false) {

					validFactions.Add(spawnGroup.SpawnGroupName, validFactionsList);

				}

				if(spawnGroup.Frequency > 0){
					
					string modID = spawnGroup.SpawnGroup.Context.ModId;
					
					if(string.IsNullOrEmpty(modID) == true){
						
						modID = "KeenSWH";
						
					}
					
					if(SpawnGroupSublists.ContainsKey(modID) == false){
						
						SpawnGroupSublists.Add(modID, new List<ImprovedSpawnGroup>());
						
					}
					
					if(EligibleSpawnsByModId.ContainsKey(modID) == false){
						
						EligibleSpawnsByModId.Add(modID, 1);
						
					}else{
						
						EligibleSpawnsByModId[modID] += 1;
						
					}

					if(Settings.PlanetaryCargoShips.UseMaxSpawnGroupFrequency == true && spawnGroup.Frequency > Settings.PlanetaryCargoShips.MaxSpawnGroupFrequency * 10){
						
						spawnGroup.Frequency = (int)Math.Round((double)Settings.PlanetaryCargoShips.MaxSpawnGroupFrequency * 10);
						
					}
					
					for(int i = 0; i < spawnGroup.Frequency; i++){
						
						eligibleGroups.Add(spawnGroup);
						SpawnGroupSublists[modID].Add(spawnGroup);
						
					}
					
				}
				
			}
			
			return eligibleGroups;
			
		}
			
	}
	
}